package main

import (
	"bufio"
	"fmt"
	"os"
)

// defer 语句是go用的一种注册延迟运行调用机制，他可以让当前函数执行完后才被顺序调用，按照前进后出的顺序，相对于python中的with
func main() {
	f, _ := os.Open("../../hello.txt")
	defer f.Close() // defer 之后只能是函数调用 不能是表达式 如 a++
	scanner := bufio.NewScanner(f)
	// 相当于while
	for scanner.Scan() {
		fmt.Println(scanner.Text())
	}
	// defer 是栈里运行的 先进后出 栈可以理解为一个桶 只有一个口 先进去进到桶底了，
	defer fmt.Println("test 11")
	defer fmt.Println("test 22")
	defer fmt.Println("test 33")
	// defer 语句执行时的拷贝机制
	test := func() {
		fmt.Println("func test1")
	}
	// 【运行到此处后 已经把test压入栈中，所以后面的test更改不起作用】
	defer test() // 此处会调用test 会输出  func test1 还是 func test2 ？
	test = func() {
		fmt.Println("func test2")
	}
	fmt.Println("test 3")
	test()
	main1()
	main2()
	main3()
	fmt.Println(main4())
}

// 以下代码会输出 10 还是 11? ，因为defer的压栈机制，当运行到defer时 x=10和函数已经被压入栈中，所以输出10
func main1() {
	// defer 语句执行时拷贝
	x := 10
	defer func(a int) {
		fmt.Println(a)
	}(x) // 此处定义了匿名函数同时加上参数自运行，要不只是定义会出错
	x++
}

// 以下代码会输出 10 还是 11? 因为defer的压栈机制，当运行到defer时 x的引用被传入函数然后压入栈中，所以输出的是x的地址的值所以是11
func main2() {
	// defer 语句执行时拷贝
	x := 10
	defer func(a *int) {
		fmt.Println(*a)
	}(&x) // 此处定义了匿名函数同时加上参数自运行，要不只是定义会出错
	x++
}

// 以下代码会输出 10 还是 11? 因为defer并没有参数，函数内部使用的值是全局的值x，而并不是上个例子中的参数局部变量a，所以会输出x++后的值11，闭包特性
func main3() {
	// defer 语句执行时拷贝
	x := 10
	defer func() {
		fmt.Println(x)
	}() // 此处定义了匿名函数同时加上参数自运行，要不只是定义会出错
	x++
}

//  以下代码会输出 10 还是 11?  因为函数在return前会把当前的返回值 赋给一个临时变量来保存，然后再去延迟栈里按照顺序执行defer代码，执行完后把保存的值返回
//  所以可以理解return值在defer执行前已经被保存起来了，所以defer无法修改return的值，除非是引用类型 所以输出10
func main4() int {
	x := 10
	defer func() {
		x++
	}()
	return x
}
